package com.bwda.dsrs.filecenter.service.impl;


import com.bwda.dsrs.base.util.StringUtil;
import com.bwda.dsrs.filecenter.domain.po.executionpolicy.ExecutionPolicyPo;
import com.bwda.dsrs.filecenter.service.ExecutionPolicyService;
import com.bwda.dsrs.filecenter.service.ResAuditTaskExecutionService;
import com.bwda.dsrs.filecenter.util.DateTimeUtils;
import com.bwda.dsrs.systemservice.domain.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 稽核任务统一执行类

 *
 * @author xxx
 * @date 2020/07/17
 **/
@Service
public class ResAuditTaskExecutionServiceImpl implements ResAuditTaskExecutionService {

    private static Logger logger = LoggerFactory.getLogger(ResAuditTaskExecutionServiceImpl.class);

    @Autowired
    private ExecutionPolicyService resAuditTaskCnfgService;

    /**
     * 任务执行线程
     */
    private static final ThreadPoolExecutor THREAD_POOL = new ThreadPoolExecutor(5, 10, 5,
            TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
            new ThreadPoolExecutor.DiscardOldestPolicy());

    /**
     * 定时执行稽核任务
     *
     * @return boolean
     */
    @Override
    public boolean timerExecute() {
        //获取当前需执行的任务列表
        List<ExecutionPolicyPo> executeTaskList = queryAllResAuditTask();
        if (executeTaskList == null || executeTaskList.size() == 0) {
            //无需要执行的任务
            return false;
        }
        //定时自动执行的任务，启动任务前，先将该任务的最后一次执行时间更新为当前时间
        for (ExecutionPolicyPo executeTaskPo : executeTaskList) {
            resAuditTaskCnfgService.updateTaskExecutionTime(executeTaskPo.getExecutionPolicyId(), DateTimeUtils.getDateTime());
        }
        //开始执行任务
        boolean result = executeTask(executeTaskList, Constants.ResAuditExecutionType.ET_IMMEDIATE);
        return result;
    }

    /**
     * 立即执行指定的稽核任务
     *
     * @param executeTaskList 需执行的任务列表
     * @return boolean
     */
    @Override
    public boolean immediateExecute(List<ExecutionPolicyPo> executeTaskList) {
        if (executeTaskList == null || executeTaskList.size() == 0) {
            //无需要执行的任务
            return false;
        }

        //立即执行的任务，启动任务前，不需要将任务的最后一次执行时间更新为当前时间
        //开始执行任务
        boolean result = executeTask(executeTaskList, Constants.ResAuditExecutionType.ET_IMMEDIATE);

        return result;
    }

    /**
     * 执行稽核任务
     *
     * @param executeTaskList 待执行的任务列表
     * @param executionType   执行方式 1:由页面触发的任务立即执行 2:由定时任务触发的定时执行
     * @return
     */
    private boolean executeTask(List<ExecutionPolicyPo> executeTaskList, Long executionType) {
        if (executeTaskList == null || executeTaskList.size() == 0) {
            //无需要执行的任务
            logger.info("没有需要执行的任务--execute audit tasks:{}", executeTaskList);
            return false;
        }

        logger.info("execute audit tasks:{}", executeTaskList);


        //循环遍历executeTaskList，根据任务类型，以线程方式单独启动每个任务 1:全量 2：增量
        for (ExecutionPolicyPo executeTaskPo : executeTaskList) {
            THREAD_POOL.execute(new ResAuditConnectionTaskServiceImpl(executeTaskPo, executionType));

        }

        return true;
    }


    /**
     * 获取当前需执行的任务列表
     *
     * @return List
     */
    private List<ExecutionPolicyPo> queryAllResAuditTask() {
        //获取状态为启用的所有任务列表
        List<ExecutionPolicyPo> allTaskList = resAuditTaskCnfgService.selectResCanRunAuditTaskCnfg();

        //循环遍历任务列表,根据当前任务的执行周期和时间,判断该任务是否需要执行
        List<ExecutionPolicyPo> executeTaskList = new ArrayList<>();
        for (ExecutionPolicyPo po : allTaskList) {
            if (checkTaskWillBeExecuted(po)) {
                executeTaskList.add(po);
            }
        }

        return executeTaskList;
    }

    /**
     * 检测该任务当前是否需要执行
     *
     * @param po 任务对象
     * @return boolean
     */
    private boolean checkTaskWillBeExecuted(ExecutionPolicyPo po) {
        if (po == null || po.getExecutionCycleTypeId() == null) {
            return false;
        }

        //任务创建时间
        Date createTime = po.getCreateTime();
        //偏移的小时数
        int hourOffset = 0;
        int currDay = DateTimeUtils.getDay(hourOffset);
        int currWeek = DateTimeUtils.getWeek(hourOffset);
        int currQuarter = DateTimeUtils.getQuarterDay();
        int betweenDay = DateTimeUtils.getBetweenDay(createTime);
        String currDate = DateTimeUtils.getDate();
        String currDateTime = DateTimeUtils.getDateTime();

        if (Constants.ResAuditCycleType.CT_IMMEDIATE.equals(po.getExecutionCycleTypeId())) {
            //立即执行的任务类型，不需要执行
            return false;
        } else if (Constants.ResAuditCycleType.CT_TIMING.equals(po.getExecutionCycleTypeId())) {
            //定时执行的任务类型
            int compareResult = DateTimeUtils.compareDateTime(currDateTime, po.getExecutionTime());
            if (compareResult < 2 && StringUtil.isEmpty(po.getLastExecutionTime())) {
                //最后一次执行时间为空，且当前时间大于等于任务配置的执行时间
                return true;
            } else {
                return false;
            }
        } else if (Constants.ResAuditCycleType.CT_DAY.equals(po.getExecutionCycleTypeId())) {
            //每天执行的任务类型
            int compareResult = DateTimeUtils.compareDateTime(currDateTime, currDate + Constants.STRING_BLANK + po.getExecutionTime());
            if (compareResult < 2
                    && (StringUtil.isEmpty(po.getLastExecutionTime()) || DateTimeUtils.compareDate(currDateTime, po.getLastExecutionTime()) == 1)) {
                //当前时间大于等于任务配置的执行时间,且最后一次执行时间为空或最后一次执行时间不为当天
                return true;
            } else {
                return false;
            }
        } else if (Constants.ResAuditCycleType.CT_WEEK.equals(po.getExecutionCycleTypeId())) {
            //每周执行的任务类型
            if (currWeek == po.getExecutionDay()
                    && DateTimeUtils.compareDateTime(currDateTime, currDate + Constants.STRING_BLANK + po.getExecutionTime()) < 2
                    && (StringUtil.isEmpty(po.getLastExecutionTime()) || DateTimeUtils.compareDate(currDateTime, po.getLastExecutionTime()) == 1)) {
                //当前星期为配置的星期,且当前时间大于等于任务配置的执行时间,且最后一次执行时间为空或最后一次执行时间不为当天
                return true;
            } else {
                return false;
            }
        } else if (Constants.ResAuditCycleType.CT_MONTH.equals(po.getExecutionCycleTypeId())) {
            //每月执行的任务类型
            if (currDay == po.getExecutionDay()
                    && DateTimeUtils.compareDateTime(currDateTime, currDate + Constants.STRING_BLANK + po.getExecutionTime()) < 2
                    && (StringUtil.isEmpty(po.getLastExecutionTime()) || DateTimeUtils.compareDate(currDateTime, po.getLastExecutionTime()) == 1)) {
                //当前天数为配置的天数,且当前时间大于等于任务配置的执行时间,且最后一次执行时间为空或最后一次执行时间不为当天
                return true;
            } else {
                return false;
            }
        } else if (Constants.ResAuditCycleType.CT_QUARTER.equals(po.getExecutionCycleTypeId())) {
            //每季度执行的任务类型
            if (currQuarter == po.getExecutionDay()
                    && DateTimeUtils.compareDateTime(currDateTime, currDate + Constants.STRING_BLANK + po.getExecutionTime()) < 2
                    && (StringUtil.isEmpty(po.getLastExecutionTime()) || DateTimeUtils.compareDate(currDateTime, po.getLastExecutionTime()) == 1)) {
                //当前天数为配置的天数,且当前时间大于等于任务配置的执行时间,且最后一次执行时间为空或最后一次执行时间不为当天
                return true;
            } else {
                return false;
            }
        } else if (Constants.ResAuditCycleType.CT_PERIODIC.equals(po.getExecutionCycleTypeId())) {
            int index = (int) (betweenDay % po.getExecutionDay());
            //周期性执行的任务类型
            if (index == 0
                    && DateTimeUtils.compareDateTime(currDateTime, currDate + Constants.STRING_BLANK + po.getExecutionTime()) < 2
                    && (StringUtil.isEmpty(po.getLastExecutionTime()) || DateTimeUtils.compareDate(currDateTime, po.getLastExecutionTime()) == 1)) {
                //当前时间减去创建时间为配置的周期天数的倍数,且当前时间大于等于任务配置的执行时间,且最后一次执行时间为空或最后一次执行时间不为当天
                return true;
            } else {
                return false;
            }
        }

        return false;
    }
}
